
;--- implements Int 31h services (general)
;--- also included functions:
;--- ax=04xx (dpmi host capabilities/version)
;--- ax=06xx (virtual memory)
;--- ax=07xx (swapping)
;--- ax=09xx (virtual interrupt flag)

	.386P

	include hdpmi.inc
	include external.inc

	option proc:private

	@seg CONST32

_TEXT32 segment

	@ResetTrace

;*** INT 31h API dispatcher
;--- intr31: address in IDT if ?FASTINT31=0

intr31  proc public
ife ?FASTINT31
	push offset iret_with_CF_mod
else
	cmp word ptr cs:r3vect31._Cs,_INTSEL_	;vector modified?
	jz intr31_
	cmp word ptr [esp].IRET32.rCS, _CSSEL_	;is it an internal call?
	jz intr31_								;then dont route to ring 3
	@simintpms 31
endif
intr31 endp

;--- intr31_: address in IDT if ?FASTINT31=1

intr31_ proc public
if 0;_LTRACE_
	cmp ah,9
	jz @F
	@dprintf "i31 enter a-d=%X %lX %lX %lX esi=%lX edi=%lX hs=%lX",ax,ebx,ecx,edx,esi,edi,esp
@@:
endif
	push ds
	call _i31srvr
	pop ds
if 0;_LTRACE_
	jc @F
	@dprintf "#i31 exit NC "
	jmp intr31ex_1
@@:
	@dprintf "#i31 exit C  "
intr31ex_1:
	@dprintf <"a-d=%X %lX %lX %lX esi=%lX edi=%lX">,ax,ebx,ecx,edx,esi,edi
endif
if ?FASTINT31
	jmp iret_with_CF_mod
else
	ret
endif
	align 4
intr31_ endp

;--- support DPMI 1.0: 
;--- 000E, 000F
;--- (0210, 0212) [DPMI10EXX]
;--- 0401
;--- 0504, 0505, 0506, 0507 (,0508, 0509, 050A, 050B) [DPMI10EX]
;--- 0801

?FUNC00 = 0Eh
?FUNC02 = 06h
?FUNC04 = 01h
?FUNC05 = 04h
?FUNC08 = 01h

if ?DPMI10
?FUNC00 = 10h
if ?DPMI10EXX
?FUNC02 = 14h
endif
?FUNC04 = 02h
?FUNC05 = 08h
if ?DPMI10EX
?FUNC05 = 0Ch
endif
?FUNC08 = 02h
endif

subfunctab label byte
	db ?FUNC00			;00
	db 03h				;01
	db ?FUNC02,07h		;02-03
	db ?FUNC04			;04
dpmi5functions db ?FUNC05	;05 (may be modified while this code is low)
	db 05h,04h			;06-07
	db ?FUNC08			;08
	db 03h,00h,04h		;09-0B
	db 00h,00h,02h		;0C-0E

	align 4

@defl macro x
	exitm <offset x>
	endm

CONST32 segment

functab label dword
	dd @defl(func00), @defl(func01), @defl(func02), @defl(func03)
	dd @defl(func04), @defl(func05), @defl(func06), @defl(func07)
	dd @defl(func08), @defl(func09), @defl(func0A), @defl(func0B)
	dd @defl(func0C), @defl(func0D), @defl(i31f0E)

jmpvector0 label dword
	dd @defl(allocsel)	;0
	dd @defl(freesel)	;1
	dd @defl(allocrmsel);2
	dd @defl(getincvalue);3
	dd @defl(locksel)	;4
	dd @defl(unlocksel) ;5
	dd @defl(getbase)	;6
	dd @defl(setbase)	;7
	dd @defl(setlimit)	;8
	dd @defl(setaccrights);9
	dd @defl(getcsalias);A
	dd @defl(getdesc)	;B
	dd @defl(setdesc)	;C
	dd @defl(allocspecific)  ;D
if ?DPMI10
	dd @defl(getmultdesc);E
	dd @defl(setmultdesc);F
endif

jmpvector1 label dword
	dd @defl(allocdos)  ;0
	dd @defl(freedos)	;1
	dd @defl(resizedos) ;2

jmpvector2 label dword
	dd @defl(getrmivec) ;0
	dd @defl(setrmivec) ;1
	dd @defl(getpmevec) ;2
	dd @defl(setpmevec) ;3
	dd @defl(getpmivec) ;4
	dd @defl(setpmivec) ;5
if ?DPMI10EXX
	dd @defl(error02)	;6
	dd @defl(error02)	;7
	dd @defl(error02)	;8
	dd @defl(error02)	;9
	dd @defl(error02)	;A
	dd @defl(error02)	;B
	dd @defl(error02)	;C
	dd @defl(error02)	;D
	dd @defl(error02)	;E
	dd @defl(error02)	;F
	dd @defl(geteexcp)  ;10
	dd @defl(geteexcr)  ;11
	dd @defl(seteexcp)  ;12
	dd @defl(seteexcr)  ;13
endif

jmpvector3 label dword
	dd @defl(_callrmproc);0
	dd @defl(_callrmproc);1
	dd @defl(_callrmproc);2
	dd @defl(allocrmcb) ;3
	dd @defl(freermcb)  ;4
	dd @defl(getsraddr) ;5 Get State Save/Restore Addresses
	dd @defl(getrmsa)	;6

jmpvector5 label dword
	dd @defl(getmeminfo);0500
	dd @defl(allocmem)  ;0501
	dd @defl(freemem)	;0502
	dd @defl(resizemem) ;0503
if ?DPMI10
	dd @defl(allocmemx)	;0504
	dd @defl(resizememx);0505
	dd @defl(getpageattr);0506
	dd @defl(setpageattr);0507
  if ?DPMI10EX
	dd @defl(mapphysx) 	;0508
	dd @defl(mapdos)	;0509
	dd @defl(getmemsize);050A
	dd @defl(getmeminfox);050B
  endif
endif

if 0
jmpvector9 label dword
	dd @defl(disableint)
	dd @defl(enableint)
	dd @defl(getintstate)
endif

jmpvectorB label dword
	dd @defl(allocwatchp)
	dd @defl(clearwatchp)
	dd @defl(getwatchpstate)
	dd @defl(resetwatchpstate)

if 0
jmpvectorE label dword
	dd @defl(getcostate)
	dd @defl(setcostate)
endif
CONST32 ends

	@ResetTrace

_i31srvr proc near

	cmp ah,0Fh
	jnb error1
	push ebx
	movzx ebx,ah
	cmp al,byte ptr cs:[ebx + offset subfunctab]
	jnc error2
	cld
	jmp dword ptr cs:[ebx*4 + offset functab]
error2:
	pop ebx
error1:
if 1
	mov ax,8001h				;unsupported function
endif
	@dprintf "int31, ax=%X unsupported, bx-di=%X %X %X %X %X",ax,bx,cx,dx,si,di
	stc
	ret
_i31srvr endp

	@ResetTrace

;--- descriptor (LDT) functions

func00:
	push offset jmpvector0
	mov ds,ss:[selLDT]
	jmp func_00_02
	align 4

;--- interrupt (IDT) functions

func02:
if ?ENHANCED
	and al,7Fh
endif
	push offset jmpvector2
	push byte ptr _FLATSEL_
	pop ds

func_00_02:
	movzx ebx,al
	shl ebx, 2
	add ebx,[esp]
	mov [esp], offset return
	push dword ptr cs:[ebx]
	mov ebx, [esp+4].I31FR1.dwEbx
	retn
return:
	pop ebx
	ret
if ?DPMI10EXX
error02:
	stc
	ret
endif
	align 4

I31FR2 struct
dwJumpVec	dd ?
dwEbx		dd ?
			dd ?	;returnaddress
dwDS		dd ?
I31FR2 ends

;--- dos memory functions

func01:
	push offset jmpvector1
	jmp func_01_03_05_0B
	align 4

;--- mode switch functions

func03:
	push offset jmpvector3
	jmp func_01_03_05_0B
	align 4

;--- watchpoint functions

func0B:
	push offset jmpvectorB
	jmp func_01_03_05_0B
	align 4

;--- extended memory functions

func05:
	push offset jmpvector5
;	push byte ptr _FLATSEL_
;	pop ds
func_01_03_05_0B:
	movzx ebx, al
	shl ebx, 2
	add ebx, [esp].I31FR2.dwJumpVec
	mov ebx, cs:[ebx]
	mov [esp].I31FR2.dwJumpVec, ebx
	mov ebx, [esp].I31FR2.dwEbx
	retn 4
	align 4

	@ResetTrace

HF_32BIT	equ 1	;running under a 32-bit implementation
HF_INTINRM	equ 2	;ints reflected to real-mode
HF_VIRTMEM	equ 4	;virtual memory supported


func04:
	pop ebx
if ?DPMI10
	and al,al
	jnz func0401
endif
	mov ax,ss:[wVersion] 
	mov bx,HF_32BIT
	test ss:[fHost], FH_VCPI
	jnz @F
	or bl,HF_INTINRM
@@:
	mov cl,ss:[_cpu]			;CPU=80386/80486
	mov dx,?MPICBASE*100h+?SPICBASE  ;PIC bases
	ret
	align 4

if ?DPMI10

DPMI10_PAGE_ACCDIRTY	equ 1	;support to get/set dirty/accessed PTE flags
DPMI10_EXCRESTART		equ 2	;allow client to handle ring 0 exceptions
DPMI10_DEVICEMAPPING	equ 4	;support int 31h, ax=0508h
DPMI10_CONVMEMMAPPING	equ 8	;support int 31h, ax=0509h
DPMI10_DEMANDZEROFILL	equ 16	;fill newly committed pages with 00
DPMI10_WRITEPROTCLIENT	equ 32	;client cannot modify r/o pages
DPMI10_WRITEPROTHOST	equ 64	;host cannot modify r/o pages

if ?EXCRESTART
HOSTCAPS equ DPMI10_PAGE_ACCDIRTY + DPMI10_EXCRESTART + \
	DPMI10_DEVICEMAPPING + DPMI10_CONVMEMMAPPING + DPMI10_WRITEPROTCLIENT
else
HOSTCAPS equ DPMI10_PAGE_ACCDIRTY + \
	DPMI10_DEVICEMAPPING + DPMI10_CONVMEMMAPPING + DPMI10_WRITEPROTCLIENT
endif

;dpmi10str	db ?VERMAJOR,?VERMINOR,"HDPMI",0
;SIZEDPMI10	equ $ - dpmi10str

;--- ax=401h
;--- in: es:e/di buffer for host string ( 128 byte )
;--- out: cx, dx, ax

func0401:
	pushad
;	mov esi, offset dpmi10str
;	mov ecx, SIZEDPMI10
ife ?32BIT
	movzx edi, di
endif
;	db 2Eh				;CS segment prefix
;	rep movsb
	mov eax, ("DH" shl 16) or (?VERMINOR shl 8) or ?VERMAJOR
	stosd
	mov eax, "IMP"
	stosd
	popad
	xor cx,cx
	xor dx,dx
;--- todo: check CR0.WP bit and set flag DPMI10_WRITEPROTHOST accordingly
	mov ax,HOSTCAPS
	cmp cs:dpmi5functions,5
	jnc @F
	mov al,DPMI10_WRITEPROTCLIENT
@@:
	clc
	ret
endif
func08: 				;map real -> virt
	pop ebx
if ?DPMI10
	cmp al,1
	jz unmapphysregion
endif
	jmp mapphysregion

;--- paging
;--- ax=0700: mark pages as paging candidates BX:CX, SI:DI
;--- ax=0701: discard pages BX:CX, SI:DI
;--- ax=0702: mark pages as demand paging candidates BX:CX, SI:DI
;--- ax=0703: discard page contents BX:CX, SI:DI

func07 proc


	pop ebx
if 0
	cmp bx,0011h			;address < 110000h?
	jb exit
	push eax
	push edx
	xor edx,edx				;reset accessed (+ dirty) flags
	test al,1
	mov ax,PTF_ACCESSED
	jz @F
	or ax,PTF_DIRTY
@@:
	call pm_setregionattributes
	pop edx
	pop eax
exit:
else
	clc		;--- just exit with NC
endif
	ret
	align 4
func07 endp

;--- virtual memory functions
;--- ax=0600: lock linear region BX:CX, size SI:DI
;--- ax=0601: unlock linear region BX:CX, size SI:DI
;--- ax=0602: mark real-mode region as pageable, BX:CX, size SI:DI
;--- ax=0603: relock real-mode region, BX:CX, size SI:DI
;--- ax=0604: return page size

func06 proc
	pop ebx
	cmp al,04			;added 29.2.2004
	jb lockunlock
	mov cx,1000h		;return page size in BX:CX
	xor bx,bx
	ret

;--- since virtual memory is not supported, dont do anything here
        
lockunlock:
	clc
	ret
func06 endp

func0A:
func0C:
func0D:
	pop ebx
	stc
	ret
	align 4

;*** int 31h, ax=09xxh ***

I3109FR struct
rEBX	dd ?
dwRet	dd ?	;_i31srvr
rDS		dd ?
ife ?FASTINT31
dwRet2	dd ?	;iret_with_CF_mod if ?FASTINT31 == 0
endif
I3109FR ends

;--- interrupt flag functions
;--- ax=0900h: disable virtual interrupt state
;--- ax=0901h: enable virtual interrupt state
;--- ax=0902h: get virtual interrupt state

;--- v3.21: VIRTIF added; if PVI is set in CR4, get/set the VIF.
;--- setting VIRTIF to 1 will cause severe incompatibilities!

ife ?PMIOPL 
VIRTIF equ 0	;1=set/reset VIF instead of IF
else
VIRTIF equ 0
endif

func09 proc
if VIRTIF
	test byte ptr ss:[dwFeatures], 2	; PVI supported?
	jz @F
	.586
	mov ebx, cr4
	.386
	test bl, 2
	mov bx, 19		; VIF
	jnz vifbitset
@@:
	mov bx, 9		; IF
vifbitset:
else
	mov bx, 9		; IF
endif
	and byte ptr [esp + sizeof I3109FR].IRET32.rFL,not 1	;clear carry
	cmp al,1
	jz enableint
	jnc getintstate
disableint:
	btr word ptr [esp + sizeof I3109FR].IRET32.rFL, bx
	jmp @F
	align 4
enableint:
	bts word ptr [esp + sizeof I3109FR].IRET32.rFL, bx
	jmp @F
	align 4
getintstate:
	bt word ptr [esp + sizeof I3109FR].IRET32.rFL, bx
@@:
	setc al
	mov ebx,[esp].I3109FR.rEBX
	add esp, sizeof I3109FR
	iretd
	align 4
func09 endp

_TEXT32 ends

	end
